package com.lancoo.cvas.arrangecourse;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.lancoo.cvas.arrangecourse.clashesprocess.ClashesProcess;
import com.lancoo.cvas.arrangecourse.common.BinaryUtil;
import com.lancoo.cvas.arrangecourse.common.ClassHourUtil;
import com.lancoo.cvas.arrangecourse.coursescheduling.SchoolScheduling;
import com.lancoo.cvas.arrangecourse.dataprocess.ClassHourScheduleConvert;
import com.lancoo.cvas.arrangecourse.dataprocess.GenerateTimeslotRoom;
import com.lancoo.cvas.arrangecourse.dataprocess.TeacherAndCourseProhibitProcess;
import com.lancoo.cvas.arrangecourse.entities.BaseRule;
import com.lancoo.cvas.arrangecourse.entities.ClassHour;
import com.lancoo.cvas.arrangecourse.entities.CourseUnit;
import com.lancoo.cvas.arrangecourse.entities.TimeslotRoom;
import com.lancoo.cvas.entity.*;
import com.lancoo.cvas.exception.CapacityException;
import com.lancoo.cvas.mapper.*;
import com.lancoo.cvas.pojo.common.Deleted;
import com.lancoo.cvas.pojo.common.FixType;
import com.lancoo.cvas.pojo.common.ScheduleState;
import com.lancoo.cvas.pojo.constant.GlobalConstant;
import com.lancoo.cvas.pojo.dto.*;
import com.lancoo.cvas.pojo.vo.TeachingClassCourseDto;
import com.lancoo.cvas.pojo.vo.WeekDateVo;
import com.lancoo.cvas.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

/**
 * @Author: liufeng
 * @CreateTime: 2023-12-12  15:18
 * @Description:
 */
@Slf4j
@Service
public class ArrangeCourseServiceImpl implements ArrangeCourseService {


    //排课数据源
    @Resource
    ArrangeCourseDataSource arrangeCourseDataSource;

    @Resource
    ClashesProcess clashesProcess;
    @Resource
    TeachingClassWeekService teachingClassWeekService;
    @Resource
    ArrangeProcessService arrangeProcessService;
    @Resource
    TeachingClassWeekMapper teachingClassWeekMapper;
    @Resource
    TaskInfoService taskInfoService;
    @Resource
    ScheduleMapper scheduleMapper;
    @Resource
    TeachingClassStudentMapper teachingClassStudentMapper;
    @Resource
    TeachingClassMapper teachingClassMapper;
    @Resource
    TeacherService teacherService;
    @Resource
    RuleClassProhibitService ruleClassProhibitService;
    @Resource
    RuleTeachingClassProhibitService ruleTeachingClassProhibitService;
    @Resource
    RuleTeacherTimeService ruleTeacherTimeService;
    @Resource
    RuleCourseProhibitMapper ruleCourseProhibitMapper;
    @Resource
    RuleTeachingClassProhibitMapper ruleTeachingClassProhibitMapper;
    @Resource
    RoomService roomService;

    ClassHourScheduleConvert convertor = null;

    public ArrangeCourseServiceImpl() {
        //初始化，类型转换的类
        convertor = new ClassHourScheduleConvert();
    }

    /**
     * 针对排课手动调整功能，获取可用的教室、课时分组信息
     *
     * @param taskId        排课计划id
     * @param weeks         当前手动调整的教学班，需要调整的周次信息(二进制字符串，如：00011000000)
     * @param timeCodes     教学班所学的课时编码，多个以逗号分隔，如：0101、1012，0303、0304（null获取全部）
     * @param roomId        教学班排课所需的教室id（null获取全部）；
     * @param teachingClass 手动调课的教学班信息
     * @return
     */
    @Override
    public LinkedList<TimeslotRoom> getAvailableTimeslotRoomList(String schoolId,
                                                                 String termId,
                                                                 Integer taskId,
                                                                 String weeks,
                                                                 String timeCodes,
                                                                 Integer buildingId,
                                                                 Long roomId,
                                                                 String keyword,
                                                                 ArrangeTeachingClassDto teachingClass) throws CapacityException {

        /*
        手动调整 不考虑固排
        获取规则设置
         */
        BaseRule baseRule = getScheduleRule(null, null, taskId, null);
        //获取教室禁排数据
        List<ArrangeRoomRuleDto> roomProhibitList = new ArrayList<>();
        if ("b".equals(baseRule.getRoomRuleEnable())) {
            roomProhibitList = arrangeCourseDataSource.getRoomRuleList(taskId, schoolId, termId, null);
        }
        //获取教师排课规则
        List<ArrangeTeacherRuleDto> teacherRuleList = new ArrayList<>();
        if ("b".equals(baseRule.getTeacherRuleEnable())) {
            teacherRuleList = arrangeCourseDataSource.getTeacherRuleList(taskId, schoolId, termId);
            if (teacherRuleList != null
                    && !teacherRuleList.isEmpty()) {
                //选出教师禁排规则
                teacherRuleList = teacherRuleList.stream()
                        .filter(teacherRule -> teacherRule.getFlag().equals(2))
                        .collect(Collectors.toList());
            }
        }
        //获取课程禁排数据
        List<ArrangeCourseRuleDto> courseProhibitList = new ArrayList<>();
        if ("b".equals(baseRule.getCourseRuleEnable())) {
            courseProhibitList = arrangeCourseDataSource.getCourseRuleList(taskId);
        }
        List<ArrangeClassRuleDto> classProhibitList = new ArrayList<>();
        if ("b".equals(baseRule.getClassRuleEnable())) {
            classProhibitList = arrangeCourseDataSource.getclassRuleList(taskId);
        }
        List<ArrangeTeachingClassRuleDto> teachingClassProhibitList = new ArrayList<>();
        if ("b".equals(baseRule.getTeachingClassRuleEnable())) {
            teachingClassProhibitList = arrangeCourseDataSource.getTeachingClassRuleList(taskId)
                    .stream().filter(o -> o.getFlag() == 2)
                    .collect(Collectors.toList());
        }


        //获取排课教室数据
        List<ArrangeRoomDto> roomList = arrangeCourseDataSource.getRoomList(schoolId, termId, null);
        //获取排课课时数据；
        List<ArrangePeriod> timeslotList = arrangeCourseDataSource.getTimeslotList(taskId, schoolId, termId);
        //获取本学期所有计划的课表信息
        List<ArrangeScheduleDto> lockedScheduleList = arrangeCourseDataSource.getLockedScheduleList(
                taskId, null, null, null);

        /*
        解决 从0101 调整到 0101问题
            获取可用教室课时  同一个timecode转换问题 优化 未解决（同一个教室：啥也没改 过滤掉，好几次排课的课时问题）
         */
//        Iterator<ArrangeScheduleDto> iterator = lockedScheduleList.iterator();
//        while (iterator.hasNext()) {
//            ArrangeScheduleDto schedule = iterator.next();
//            //第一次 第二次排课的问题  会把所有课表全删除
//            if (schedule.getTeachingClassId().equals(teachingClass.getTeachingClassId())
//                    && schedule.getHourType().equals(teachingClass.getHourType())
//                    && StrUtil.isNotEmpty(schedule.getTimeCode())){
//                String week = teachingClass.getWeek();
//                String scheduleWeek = schedule.getWeek();
//                if (scheduleWeek.equals(week)){
//                    iterator.remove();
//                }
////                else {
////                    String updateWeek = BinaryUtil.binaryXOR(scheduleWeek, week);
////                    schedule.setWeek(updateWeek);
////                }
//            }
//        }


        //将获取的锁定的课表，转换成ClassHour排课课时对象
        CopyOnWriteArrayList<ClassHour> lockedClassHourList = convertor.convertToClassHourList(lockedScheduleList, timeslotList);
        //将列表，按照timeslotCode，进行分组，即作为key，生成map
        ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> classHourMap = ClassHourUtil.getClassHourMap(lockedClassHourList);
        //获取学期的周次信息
        WeekDateVo weekInfo = arrangeCourseDataSource.getTermWeeks(taskId);
        //获取学期总周数，默认16周
        Long weekNum = 16L;
        if (weekInfo != null) {
            //获取学期总周数
            weekNum = weekInfo.getWeekCount();
        }
        //合并教室和课时信息
        LinkedList<TimeslotRoom> timeslotRoomList = new GenerateTimeslotRoom().getResult(roomList,
                timeslotList, roomProhibitList, classHourMap, weekNum);
        //如果是获取指定教学班，能用的空闲教室
        if (teachingClass != null) {
            //获取教学班所需的教师类型
            Integer filterRoomType = teachingClass.getRoomType();
            //获取教学班id
            Long teachingClassId = teachingClass.getTeachingClassId();
            //教学班容量
            Integer studentNum = teachingClass.getStudentNumber();
            //教学班排课所需的周次
            String classWeeks = teachingClass.getWeek();

            //选出指定教学班的禁排规则
            courseProhibitList = courseProhibitList.stream()
                    .filter(courseRule -> courseRule.getTeachingClassId().equals(teachingClassId)).collect(Collectors.toList());
            //将禁排的教师和课程，在对应的教学班上面做好标记；
            teachingClass = new TeacherAndCourseProhibitProcess().getResult(teachingClass,
                    courseProhibitList, teacherRuleList, classProhibitList, teachingClassProhibitList);


            //为了避免产生教师冲突  把教师的已排课时去掉(将已排课时放进禁排里面)
            teachingClass = removeTeacherScheduledTimeCodes(taskId, schoolId, termId, teachingClass);

            //为了避免产生学生冲突  把学生的已排课时去掉(将已排课时放进禁排里面)
            teachingClass = removeStudentScheduledTimeCodes(teachingClass);


            //找出周次符合当前教学班要求的课时信息
            timeslotRoomList = filterTimeslotRoomByWeeks(timeslotRoomList, classWeeks);

            //选出符合教室类型条件的教室
            String campusId = teachingClass.getCampusId();
            if (StrUtil.isNotEmpty(campusId)) {
                timeslotRoomList = timeslotRoomList.stream()
                        .filter(timeslotRoom -> timeslotRoom.getCampusId().equals(campusId))
//                        .filter(timeslotRoom -> timeslotRoom.getCapacity() >= studentNum)
                        .collect(Collectors.toCollection(LinkedList::new));

            }

            int preSize = timeslotRoomList.size();

            if (filterRoomType != null){
                timeslotRoomList = timeslotRoomList.stream()
                        .filter(timeslotRoom -> timeslotRoom.getRoomType().equals(filterRoomType))
//                        .filter(timeslotRoom -> timeslotRoom.getCapacity() >= studentNum)
                        .collect(Collectors.toCollection(LinkedList::new));

            }
            if(timeslotRoomList.size() == 0){
                throw new CapacityException(999,"教学班所需教室类型(" + GlobalConstant.roomTypeMap3.get(filterRoomType)
                        + ")的教室已全部被占用");
            }


//            timeslotRoomList = timeslotRoomList.stream()
//                    .filter(timeslotRoom -> timeslotRoom.getCapacity() >= studentNum)
//                    .collect(Collectors.toCollection(LinkedList::new));


            if (roomId != null) {
                timeslotRoomList = timeslotRoomList.stream()
                        .filter(timeslotRoom -> timeslotRoom.getRoomId().equals(roomId))
//                        .filter(timeslotRoom -> timeslotRoom.getCapacity() >= studentNum)
                        .collect(Collectors.toCollection(LinkedList::new));

            }
            if(timeslotRoomList.size() == 0){
                Room room = roomService.getById(roomId);
                String roomName = room == null ? "" : room.getRoomName();
                throw new CapacityException(999,"教学班所需的教室(" + roomName
                        + ")该课时已全部被占用");
            }

            //过滤禁排的课时
            timeslotRoomList = removePhrohibitRuleTimeslotRoom(teachingClass, timeslotRoomList);
            if(timeslotRoomList.size() == 0){
                Room room = roomService.getById(roomId);
                String roomName = room == null ? "" : "(" + room.getRoomName() + ")";
                throw new CapacityException(999,"教学班所需教室类型(" + GlobalConstant.roomTypeMap3.get(filterRoomType)
                        + ")的教室" + roomName +
                        "该课时已全部被占用");
            }

//            //找出周次符合当前教学班要求的课时信息
//            timeslotRoomList = filterTimeslotRoomByWeeks(timeslotRoomList, classWeeks);


        }

        if (timeslotRoomList != null && !timeslotRoomList.isEmpty()) {
            //筛选对应的周次以及课时编码的数据
            timeslotRoomList = timeslotRoomList.stream()
                    .filter(timeslotRoom -> StrUtil.isBlank(weeks) || weeks.equals(BinaryUtil.binaryAnd(timeslotRoom.getWeeks(), weeks)))
                    .filter(timeslotRoom -> buildingId == null || timeslotRoom.getBuildingId().equals(buildingId))
                    .filter(timeslotRoom -> roomId == null || timeslotRoom.getRoomId().equals(roomId))
                    .filter(timeslotRoom -> StrUtil.isBlank(timeCodes) || timeCodes.contains(timeslotRoom.getTimeslotCode()))
                    .filter(timeslotRoom -> StrUtil.isBlank(keyword) || timeslotRoom.getRoomName().contains(keyword) || timeslotRoom.getBuildingName().contains(keyword))
                    .collect(Collectors.toCollection(LinkedList::new));
        }
        if(timeslotRoomList.size() == 0){
            throw new CapacityException(999,"筛选的教室和课时已全部被占用");
        }

        return timeslotRoomList;
    }


    /**
     * @param taskId
     * @param schoolId
     * @param termId
     * @param teachingClass :
     * @Description: 减少产生冲突  将教学班教师已经排了的课时去除 （放进禁排课时里面）
     * @Author: liufeng
     * @Date: 2024/2/22 15:10
     * @return:
     */
    private ArrangeTeachingClassDto removeTeacherScheduledTimeCodes(Integer taskId, String schoolId, String termId, ArrangeTeachingClassDto teachingClass) {
        if (StrUtil.isNotEmpty(teachingClass.getTeacherIds())) {
            List<Integer> taskIds = taskInfoService.lambdaQuery().eq(TaskInfo::getSchoolId, schoolId)
                    .eq(TaskInfo::getTerm, termId)
                    .eq(TaskInfo::getDeleted, Deleted.NOT.getCode()).list()
                    .stream().map(TaskInfo::getTaskId).collect(Collectors.toList());
            HashSet<String> times = new HashSet<>();
            String[] teacherIdArr = teachingClass.getTeacherIds().split(",");
            for (String splitTeacherId : teacherIdArr) {
                List<ViewSchedule> schedules = scheduleMapper.getTeacherScheduledTimeCodes(taskIds, splitTeacherId);

//                //第一次 第二次排课的问题  会把所有课表全删除
//                schedules = schedules.stream()
//                        .filter(schedule ->
//                                !schedule.getTeachingClassId().equals(teachingClass.getTeachingClassId())
//                                || !schedule.getHourType().equals(teachingClass.getHourType())
//                                || !StrUtil.isNotEmpty(schedule.getTimeCode())
//                                || !schedule.getWeek().equals(teachingClass.getWeek())
//                        ).collect(Collectors.toList());

                if (CollUtil.isNotEmpty(schedules)) {
                    times.addAll(schedules.stream().map(ViewSchedule::getTimeCode).collect(Collectors.toList()));
                }
            }
            teachingClass.setProhibitTimeslotCodes(dealTimeslotCodes(teachingClass.getProhibitTimeslotCodes(),
                    new ArrayList<>(times)));
        }
        return teachingClass;
    }

    /**
     * @param teachingClass :
     * @Description: 减少产生冲突  将教学班学生已经排了的课时去除 （放进禁排课时里面）
     * @Author: liufeng
     * @Date: 2024/2/22 15:10
     * @return:
     */
    private ArrangeTeachingClassDto removeStudentScheduledTimeCodes(ArrangeTeachingClassDto teachingClass) {
        if (teachingClass.getTeachingClassId() != null) {
            List<String> times = teachingClassStudentMapper.getScheduledTimeCodes(teachingClass.getTeachingClassId());

//            List<ViewSchedule> schedules = teachingClassStudentMapper.getScheduledTimeCodes(teachingClass.getTeachingClassId());
//            //第一次 第二次排课的问题  会把所有课表全删除
//            schedules = schedules.stream()
//                    .filter(schedule ->
//                            !schedule.getTeachingClassId().equals(teachingClass.getTeachingClassId())
//                                    || !schedule.getHourType().equals(teachingClass.getHourType())
//                                    || !StrUtil.isNotEmpty(schedule.getTimeCode())
//                                    || !schedule.getWeek().equals(teachingClass.getWeek())
//                    ).collect(Collectors.toList());
//            List<String> times = schedules.stream().map(ViewSchedule::getTimeCode).distinct().collect(Collectors.toList());

            teachingClass.setProhibitTimeslotCodes(dealTimeslotCodes(teachingClass.getProhibitTimeslotCodes(),
                    new ArrayList<>(times)));
        }
        return teachingClass;
    }

    private String dealTimeslotCodes(String prohibitTimeslotCodes, List<String> times) {
        if (prohibitTimeslotCodes == null) {
            prohibitTimeslotCodes = "";
        }
        for (String time : times) {
            if (!prohibitTimeslotCodes.contains(time)) {
                prohibitTimeslotCodes += time + ",";
            }
        }
        return prohibitTimeslotCodes;
    }

    /**
     * 手动调整之后的数据更新，更新冲突表和教学班的排课冲突状态
     *
     * @param schoolId        学校id
     * @param termId          学期id
     * @param taskId          计划id
     * @param campusId        校区id
     * @param teachingClassId 教学班Id
     */
    @Override
    public void manualAdjustmentUpdate(String schoolId, String termId, Integer taskId, String campusId, Long teachingClassId) {
        //获取排课课时数据；
        List<ArrangePeriod> allTimeslotList = arrangeCourseDataSource.getTimeslotList(taskId, schoolId, termId);
        //锁定后的课表信息，为null，获取所有的课表数据
        List<ArrangeScheduleDto> scheduleList = arrangeCourseDataSource.getLockedScheduleList(taskId, campusId, null, null);
        //将获取的课表，转换成ClassHour排课课时对象
        CopyOnWriteArrayList<ClassHour> allClassHourList = convertor.convertToClassHourList(scheduleList, allTimeslotList);

        //从教学班中，筛选出当前教学班的课表信息；
        CopyOnWriteArrayList<ClassHour> teachingClassClassHourList = allClassHourList.stream()
                .filter(classHour -> classHour.getTimeslotRoom() != null)
                .filter(classHour -> classHour.getCourseUnit().getTeachingClassId().equals(teachingClassId))
                .collect(Collectors.toCollection(CopyOnWriteArrayList::new));
        //将列表，按照timeslotCode，进行分组，即作为key，生成map
        ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> classHourMap = ClassHourUtil.getClassHourMap(allClassHourList);

        //获取当前教学班的冲突数据,以及与这个教学班冲突的其他教学班的冲突数据
        List<ScheduleConflictInfo> teachingClassConflictList = arrangeCourseDataSource.getTeachingClassConflictList(teachingClassId);

        //map的key为排课单元id，即CourseUnitId
        Map<Integer, List<ScheduleConflictInfo>> conflictMap = new HashMap<>();
        //将当前教学班的排课单元，进行冲突记录
        //其实就是获取调整后教学班产生的新的冲突记录
        conflictMap = clashesProcess.recordTimeslotRoomClashes(classHourMap,
                teachingClassClassHourList, conflictMap);

        //如果map中存在数据；
        if (!conflictMap.isEmpty()) {
            //将冲突记录的map，转换成list
            List<ScheduleConflictInfo> conflictList = conflictMap.entrySet().stream()
                    .flatMap(entry -> entry.getValue().stream())
                    .collect(Collectors.toList());
            //处理与当前教学班冲突的教学班的，冲突信息以及排课状态信息
            dealWithClashesTeachingClassConflictInfo(teachingClassConflictList,
                    conflictList);

            //批量更新，不存在则添加，相应的冲突信息；
            arrangeCourseDataSource.updateAndAddConflictList(conflictList);
            //将相应教学班的排课状态，更新为已排(冲突)
            updateStateByConflictList(conflictList, ScheduleState.CONFLICT.getCode());

        } else {//没有冲突

            //如果之前存在冲突，则删除
            if (teachingClassConflictList != null && !teachingClassConflictList.isEmpty()) {
                arrangeCourseDataSource.removeConflictList(teachingClassConflictList);
                //跟新状态
                List<ScheduleConflictInfo> noConflictTeachingClass = teachingClassConflictList.stream()
                        .filter(o -> !Objects.equals(o.getTeachingClassId(), teachingClassId))
                        .collect(Collectors.toList());
                updateStateByTeachingClasss(noConflictTeachingClass, ScheduleState.NORMAL.getCode());

            }
            CopyOnWriteArrayList<ClassHour> normal = new CopyOnWriteArrayList<>(teachingClassClassHourList.stream()
                    .filter(o -> StrUtil.isNotEmpty(o.getTimeslotRoom().getTimeslotCode())
                            && o.getTimeslotRoom().getRoomId() != null).collect(Collectors.toList()));
            //将教学班的排课状态，更新为已排（无冲突）
            updateStateByClassHourList(normal, ScheduleState.NORMAL.getCode());

//            //删除课表
//            CopyOnWriteArrayList<ClassHour> unRange = new CopyOnWriteArrayList<>(teachingClassClassHourList.stream()
//                    .filter(o -> StrUtil.isEmpty(o.getTimeslotRoom().getTimeslotCode())
//                            && o.getTimeslotRoom().getRoomId() == null).collect(Collectors.toList()));
//            //将教学班的排课状态，更新为待排
//            updateStateByClassHourList(unRange, ScheduleState.UNARRANGE.getCode());

            //从教学班中，筛选出当前教学班的课表信息；
            CopyOnWriteArrayList<ClassHour> teachingClassClassNoHourList = allClassHourList.stream()
                    .filter(classHour -> classHour.getTimeslotRoom() == null)
                    .filter(classHour -> classHour.getCourseUnit().getTeachingClassId().equals(teachingClassId))
                    .collect(Collectors.toCollection(CopyOnWriteArrayList::new));
            //将教学班的排课状态，更新为待排
            updateStateByClassHourList(teachingClassClassNoHourList, ScheduleState.UNARRANGE.getCode());

        }

        //更新是否未满足规则
        if (CollUtil.isNotEmpty(teachingClassClassHourList)){
            updateRules(taskId, teachingClassId, teachingClassClassHourList);
//            ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> map = new ConcurrentHashMap<>();
//            map.put("noClash", teachingClassClassHourList);
//            updateUnsuitableScheduleState(map);
        }
    }

    /**
     * 规则调整之后的数据更新，更新教学班的排课冲突状态
     *
     * @param schoolId        学校id
     * @param termId          学期id
     * @param taskId          计划id
     * @param campusId        校区id
     * @param teachingClassIds 教学班Id
     */
    @Override
    public void manualAdjustmentUpdateRule(String schoolId, String termId, Integer taskId, String campusId, List<Long> teachingClassIds) {
        if (CollUtil.isEmpty(teachingClassIds)){
            return;
        }
        //获取排课课时数据；
        List<ArrangePeriod> allTimeslotList = arrangeCourseDataSource.getTimeslotList(taskId, schoolId, termId);
        //锁定后的课表信息，为null，获取所有的课表数据
        List<ArrangeScheduleDto> scheduleList = arrangeCourseDataSource.getScheduleListByTeachingClassIds(taskId, campusId, teachingClassIds);
        //将获取的课表，转换成ClassHour排课课时对象
        CopyOnWriteArrayList<ClassHour> allClassHourList = convertor.convertToClassHourList(scheduleList, allTimeslotList);

        BaseRule baseRule = getScheduleRule(null, null, taskId, null);
        List<TeachingClassCourseDto> teachingClassList = teachingClassMapper.getTeachingClassAndHourType(teachingClassIds);
        List<RuleTeachingClassProhibit> teachingClassRuleList = ruleTeachingClassProhibitMapper.getRuleByTeachingClass(taskId, teachingClassIds, Deleted.NOT.getCode());


        for (Long teachingClassId : teachingClassIds) {
            //从教学班中，筛选出当前教学班的课表信息；
            CopyOnWriteArrayList<ClassHour> teachingClassClassHourList = allClassHourList.stream()
                    .filter(classHour -> classHour.getTimeslotRoom() != null)
                    .filter(classHour -> classHour.getCourseUnit().getTeachingClassId().equals(teachingClassId))
                    .collect(Collectors.toCollection(CopyOnWriteArrayList::new));


            //更新是否未满足规则
            if (CollUtil.isNotEmpty(teachingClassClassHourList)){

//                updateRules(taskId, teachingClassId, teachingClassClassHourList);
                updateRules1(taskId,teachingClassId,teachingClassClassHourList,baseRule,teachingClassList,teachingClassRuleList);
            }
        }
    }

    /**
     * @Description: 获取禁排固排信息
     * @Author: liufeng
     * @Date: 2024/2/29 17:35
     * @param taskId:
     * @param teachingClassId:
     * @param teachingClassClassHourList:
     * @return:
     */
    private void updateRules(Integer taskId, Long teachingClassId, CopyOnWriteArrayList<ClassHour> teachingClassClassHourList) {
        //获取教学班
        List<TeachingClassCourseDto> teachingClassList = teachingClassMapper.getTeachingClassAndHourType(Arrays.asList(teachingClassId));
        if (CollUtil.isNotEmpty(teachingClassList)) {
//            //教师信息
//            List<Teacher> teachers = teacherService.getTeacherByTeachingClassIds(Collections.singletonList(teachingClassId));
//            Map<Long, List<Teacher>> teachingClassToTeacher = teachers
//                    .stream().collect(Collectors.groupingBy(Teacher::getTeachingClassId));


            //获取禁排信息
            BaseRule baseRule = getScheduleRule(null, null, taskId, null);

            //获取教学班规则数据 包含 固排 禁排
            List<RuleTeachingClassProhibit> teachingClassRuleList = ruleTeachingClassProhibitMapper.getRuleByTeachingClass(taskId, Collections.singletonList(teachingClassId),Deleted.NOT.getCode());

            assert baseRule != null;
            //禁排开关
            if ("a".equals(baseRule.getTeachingClassRuleEnable())) {
                //不启用时删除本身禁排信息
                //以及教学班类型固排信息删除
                if (CollUtil.isNotEmpty(teachingClassRuleList)) {
                    teachingClassRuleList = teachingClassRuleList.stream()
                            .filter(o -> o.getFlag() == 1)
                            .collect(Collectors.toList());
                }
            }
            //固排开关
            if ("a".equals(baseRule.getTeachingClassFixEnable())) {
                //不启用时删除本身禁排信息
                //以及教学班类型固排信息删除
                if (CollUtil.isNotEmpty(teachingClassRuleList)) {
                    teachingClassRuleList = teachingClassRuleList.stream()
                            .filter(o -> o.getType() != FixType.TeachingClass.getCode())
                            .collect(Collectors.toList());
                }
            }


            //教室固排不启用删除教室固排
            if ("a".equals(baseRule.getRoomFixEnable())) {
                if (CollUtil.isNotEmpty(teachingClassRuleList)) {
                    teachingClassRuleList = teachingClassRuleList.stream()
                            .filter(o -> o.getType() != FixType.Room.getCode())
                            .collect(Collectors.toList());
                }
            }

            //教师规则
//            List<RuleTeacherTime> teacherRuleList = new ArrayList<>();
//            if ("b".equals(baseRule.getTeacherRuleEnable())) {
//                //获取教师排课规则
//                if(CollUtil.isNotEmpty(teachers)){
//                    teacherRuleList = ruleTeacherTimeService.lambdaQuery()
//                            .eq(RuleTeacherTime::getTaskId, taskId)
//                            .in(RuleTeacherTime::getTeacherId, teachers.stream().map(Teacher::getTeacherId).collect(Collectors.toList()))
//                            .list();
//                }
//            }
            //教师固排不启用删除教师固排
            if ("a".equals(baseRule.getTeacherFixEnable())) {
                if (CollUtil.isNotEmpty(teachingClassRuleList)) {
                    teachingClassRuleList = teachingClassRuleList.stream()
                            .filter(o -> o.getType() != FixType.Teacher.getCode())
                            .collect(Collectors.toList());
                }
            }

            /*
            课程
             */
//            List<ArrangeCourseRuleDto> courseRuleList = new ArrayList<>();
//            if ("b".equals(baseRule.getCourseRuleEnable())) {
//                //获取课程禁排数据
//                courseRuleList = ruleCourseProhibitMapper.getCourseRuleByTeachingClass(taskId, teachingClassId);
//            }
            //课程固排不启用删除课程固排
            if ("a".equals(baseRule.getCourseFixEnable())) {
                if (CollUtil.isNotEmpty(teachingClassRuleList)) {
                    teachingClassRuleList = teachingClassRuleList.stream()
                            .filter(o -> o.getType() != FixType.Course.getCode())
                            .collect(Collectors.toList());
                }
            }

            /*
            行政班
             */
//            List<RuleClassProhibit> classProhibits = new ArrayList<>();
//            if ("b".equals(baseRule.getClassRuleEnable())) {
//                //获取行政班禁排数据
//                String classId = teachingClassList.get(0).getClassId();
//                if (StrUtil.isNotEmpty(classId)) {
//                    classProhibits = ruleClassProhibitService.lambdaQuery()
//                            .in(RuleClassProhibit::getClassId, Arrays.stream(classId.split(",")).collect(Collectors.toList()))
//                            .eq(RuleClassProhibit::getDeleted, Deleted.NOT.getCode())
//                            .eq(RuleClassProhibit::getFlag, 2).list();
//                }
//            }
            //行政班固排不启用删除行政班固排
            if ("a".equals(baseRule.getClassFixEnable())) {
                if (CollUtil.isNotEmpty(teachingClassRuleList)) {
                    teachingClassRuleList = teachingClassRuleList.stream()
                            .filter(o -> o.getType() != FixType.Class.getCode())
                            .collect(Collectors.toList());
                }
            }

            Map<Integer, List<ClassHour>> typeMap = teachingClassClassHourList.stream()
                    .collect(Collectors.groupingBy(o -> o.getCourseUnit().getTeachingType()));

            List<Integer> unSuitTypes = new ArrayList<>();
            List<Integer> normalTypes = new ArrayList<>();

            for (Integer type : typeMap.keySet()) {
                List<ClassHour> classHourList = typeMap.getOrDefault(type, new ArrayList<>());
                if (CollUtil.isNotEmpty(classHourList)){
                    //获取固排规则
                    List<String> ruleTimes = teachingClassRuleList.stream()
                            .filter(o -> o.getFlag() == 1
                                    && Objects.equals(o.getHourType(), type))
                            .map(RuleTeachingClassProhibit::getTimeCode)
                            .collect(Collectors.toList());
                    //获取课表
                    List<String> scheduleTimes = classHourList.stream().map(o -> o.getTimeslotRoom().getTimeslotCode())
                            .filter(StrUtil::isNotEmpty)
                            .collect(Collectors.toList());
                    Optional<TeachingClassCourseDto> first = teachingClassList.stream().filter(o -> o.getHourType().equals(type))
                            .findFirst();
                    if (first.isPresent()
//                            && CollUtil.isNotEmpty(ruleTimes)
                            && (first.get().getState() == ScheduleState.NORMAL.getCode()
                            || first.get().getState() == ScheduleState.UNSUITABLE.getCode())
                    ){
                        //没有规则 正常
                        if (CollUtil.isEmpty(ruleTimes)){
                            normalTypes.add(type);
                            continue;
                        }
                        //有规则
                        if (CollUtil.isNotEmpty(scheduleTimes)){
                            if (scheduleTimes.size() >= ruleTimes.size()){
                                List<String> unSuitTimes = CollUtil.subtractToList(ruleTimes, scheduleTimes);
                                if (CollUtil.isNotEmpty(unSuitTimes)){
                                    unSuitTypes.add(type);
                                }
                            }else {
                                List<String> unSuitTimes = CollUtil.subtractToList(ruleTimes, scheduleTimes);
                                if (ruleTimes.size() - unSuitTimes.size() < scheduleTimes.size()){
                                    if (CollUtil.isNotEmpty(unSuitTimes)){
                                        unSuitTypes.add(type);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            if (!unSuitTypes.isEmpty()){
                teachingClassWeekService.lambdaUpdate()
                        .eq(TeachingClassWeek::getTeachingClassId,teachingClassId)
                        .in(TeachingClassWeek::getHourType,unSuitTypes)
                        .set(TeachingClassWeek::getScheduleState,ScheduleState.UNSUITABLE.getCode())
                .update();
            }

            if (!normalTypes.isEmpty()){
                teachingClassWeekService.lambdaUpdate()
                        .eq(TeachingClassWeek::getTeachingClassId,teachingClassId)
                        .in(TeachingClassWeek::getHourType,normalTypes)
                        .set(TeachingClassWeek::getScheduleState,ScheduleState.NORMAL.getCode())
                        .update();
            }

            /*
            //把所有规则加入到教学班上
            for (ClassHour classHour : teachingClassClassHourList) {
                CourseUnit courseUnit = classHour.getCourseUnit();
                //设置教师
                List<Teacher> teacher = teachingClassToTeacher.getOrDefault(courseUnit.getTeachingClassId(),new ArrayList<>());
                String teacherIds = teacher.stream()
                        .filter(t -> Objects.equals(t.getTeacherType(), courseUnit.getTeachingType()))
                        .map(Teacher::getTeacherId).collect(Collectors.toList())
                        .stream().map(String::valueOf).collect(Collectors.joining(","));
                courseUnit.setTeacherIds(teacherIds);

                //设置禁排
                HashSet<String> pTime = new HashSet<>();
                pTime.addAll(teachingClassRuleList.stream()
                        .filter(o -> o.getFlag() == 2)
                        .map(RuleTeachingClassProhibit::getTimeCode)
                        .collect(Collectors.toList()));
                pTime.addAll(teacherRuleList.stream()
                        .filter(o -> o.getFlag() == 2)
                        .map(RuleTeacherTime::getTimeCode).collect(Collectors.toList()));
                pTime.addAll(courseRuleList.stream()
                        .filter(o -> o.getFlag() == 2)
                        .map(ArrangeCourseRuleDto::getTimeCode).collect(Collectors.toList()));
                pTime.addAll(classProhibits.stream()
                        .filter(o -> o.getFlag() == 2)
                        .map(RuleClassProhibit::getTimeCode).collect(Collectors.toList()));
                courseUnit.setProhibitTimeslotCodes(dealTimeslotCodes(courseUnit.getProhibitTimeslotCodes(),
                        new ArrayList<>(pTime)));
                //设置固排
                courseUnit.setFixTimeslotCodes(teachingClassRuleList.stream()
                        .filter(o -> o.getFlag() == 1
                                && Objects.equals(o.getHourType(), courseUnit.getTeachingType()))
                        .map(RuleTeachingClassProhibit::getTimeCode)
                        .collect(Collectors.toList()));

                TeachingClassCourseDto teachingClassCourseDto = teachingClassList.stream()
                        .filter(o -> Objects.equals(o.getHourType(), courseUnit.getTeachingType()))
                        .findFirst().orElse(null);
                if (teachingClassCourseDto != null){
                    courseUnit.setRoomId(String.valueOf(teachingClassCourseDto.getRoomId()));
                }

            }
            */
        }
    }



    private void updateRules1(Integer taskId, Long teachingClassId, CopyOnWriteArrayList<ClassHour> teachingClassClassHourList,
                              BaseRule baseRule, List<TeachingClassCourseDto> teachingClassList, List<RuleTeachingClassProhibit> teachingClassRuleList) {
        //获取教学班
        teachingClassList = teachingClassList.stream().filter(o -> o.getTeachingClassId().equals(teachingClassId)).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(teachingClassList)) {

            //获取教学班规则数据
            teachingClassRuleList = teachingClassRuleList.stream().filter(o -> o.getTeachingClassId().equals(teachingClassId)).collect(Collectors.toList());

            assert baseRule != null;
            //固排开关
            if ("a".equals(baseRule.getTeachingClassFixEnable())) {
                //不启用时删除本身禁排信息
                //以及教学班类型固排信息删除
                if (CollUtil.isNotEmpty(teachingClassRuleList)) {
                    teachingClassRuleList = teachingClassRuleList.stream()
                            .filter(o -> o.getType() != FixType.TeachingClass.getCode())
                            .collect(Collectors.toList());
                }
            }

            //教室固排不启用删除教室固排
            if ("a".equals(baseRule.getRoomFixEnable())) {
                if (CollUtil.isNotEmpty(teachingClassRuleList)) {
                    teachingClassRuleList = teachingClassRuleList.stream()
                            .filter(o -> o.getType() != FixType.Room.getCode())
                            .collect(Collectors.toList());
                }
            }

            //教师固排不启用删除教师固排
            if ("a".equals(baseRule.getTeacherFixEnable())) {
                if (CollUtil.isNotEmpty(teachingClassRuleList)) {
                    teachingClassRuleList = teachingClassRuleList.stream()
                            .filter(o -> o.getType() != FixType.Teacher.getCode())
                            .collect(Collectors.toList());
                }
            }

            //课程固排不启用删除课程固排
            if ("a".equals(baseRule.getCourseFixEnable())) {
                if (CollUtil.isNotEmpty(teachingClassRuleList)) {
                    teachingClassRuleList = teachingClassRuleList.stream()
                            .filter(o -> o.getType() != FixType.Course.getCode())
                            .collect(Collectors.toList());
                }
            }

            //行政班固排不启用删除行政班固排
            if ("a".equals(baseRule.getClassFixEnable())) {
                if (CollUtil.isNotEmpty(teachingClassRuleList)) {
                    teachingClassRuleList = teachingClassRuleList.stream()
                            .filter(o -> o.getType() != FixType.Class.getCode())
                            .collect(Collectors.toList());
                }
            }

            Map<Integer, List<ClassHour>> typeMap = teachingClassClassHourList.stream()
                    .collect(Collectors.groupingBy(o -> o.getCourseUnit().getTeachingType()));

            List<Integer> unSuitTypes = new ArrayList<>();
            List<Integer> normalTypes = new ArrayList<>();

            for (Integer type : typeMap.keySet()) {
                List<ClassHour> classHourList = typeMap.getOrDefault(type, new ArrayList<>());
                if (CollUtil.isNotEmpty(classHourList)){
                    //获取固排规则
                    List<String> ruleTimes = teachingClassRuleList.stream()
                            .filter(o -> o.getFlag() == 1
                                    && Objects.equals(o.getHourType(), type))
                            .map(RuleTeachingClassProhibit::getTimeCode)
                            .collect(Collectors.toList());
                    //获取课表
                    List<String> scheduleTimes = classHourList.stream().map(o -> o.getTimeslotRoom().getTimeslotCode())
                            .filter(StrUtil::isNotEmpty)
                            .collect(Collectors.toList());
                    Optional<TeachingClassCourseDto> first = teachingClassList.stream().filter(o -> o.getHourType().equals(type))
                            .findFirst();
                    if (first.isPresent()
                            && (first.get().getState() == ScheduleState.NORMAL.getCode()
                            || first.get().getState() == ScheduleState.UNSUITABLE.getCode())){
                        //没有规则 正常
                        if (CollUtil.isEmpty(ruleTimes)){
                            normalTypes.add(type);
                            continue;
                        }
                        //有规则
                        if (CollUtil.isNotEmpty(scheduleTimes)){
                            //课表比规则多，满足所有规则才是正常
                            if (scheduleTimes.size() >= ruleTimes.size()){
                                List<String> unSuitTimes = CollUtil.subtractToList(ruleTimes, scheduleTimes);
                                if (CollUtil.isNotEmpty(unSuitTimes)){
                                    unSuitTypes.add(type);
                                }
                            }else {
                                //课表没有规则多，满足一部分规则就是是正常
                                List<String> unSuitTimes = CollUtil.subtractToList(ruleTimes, scheduleTimes);
                                if (ruleTimes.size() - unSuitTimes.size() < scheduleTimes.size()){
                                    if (CollUtil.isNotEmpty(unSuitTimes)){
                                        unSuitTypes.add(type);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            //未满足规则
            if (!unSuitTypes.isEmpty()){
                teachingClassWeekService.lambdaUpdate()
                        .eq(TeachingClassWeek::getTeachingClassId,teachingClassId)
                        .in(TeachingClassWeek::getHourType,unSuitTypes)
                        .set(TeachingClassWeek::getScheduleState,ScheduleState.UNSUITABLE.getCode())
                        .update();
            }

            //正常
            if (!normalTypes.isEmpty()){
                teachingClassWeekService.lambdaUpdate()
                        .eq(TeachingClassWeek::getTeachingClassId,teachingClassId)
                        .in(TeachingClassWeek::getHourType,normalTypes)
                        .set(TeachingClassWeek::getScheduleState,ScheduleState.NORMAL.getCode())
                        .update();
            }
        }
    }


    /**
     * 根据课表信息列表，更新教学班的排课状态
     *
     * @param classHourList 课表信息列表
     * @param scheduleState 更新状态，1已排（正常）、2已排（冲突）、3待排
     */
    private void updateStateByClassHourList(CopyOnWriteArrayList<ClassHour> classHourList,
                                            Integer scheduleState) {
        if (classHourList != null && !classHourList.isEmpty()) {
            //提取列表中的教学班id，并去重，生成列表
            List<CourseUnit> collect = classHourList.stream()
                    .map(classHour -> classHour.getCourseUnit())
                    .collect(Collectors.toList());

            //更新教学班排课状态
            updateSchedualState(scheduleState, collect);
        }
    }

    /**
     * 处理与当前教学班冲突的教学班的，冲突信息以及排课状态信息
     * 即：调整
     *
     * @param teachingClassConflictList 调整前，当前教学班以及与当前教学班冲突的教学班，的冲突信息；
     * @param conflictList              调整后，当前教学班以及与当前教学班冲突的教学班，的冲突信息列表；
     */
    @Override
    public void dealWithClashesTeachingClassConflictInfo(List<ScheduleConflictInfo> teachingClassConflictList,
                                                         List<ScheduleConflictInfo> conflictList) {
        //处理与当前教学班冲突的教学班的冲突更新情况
        if (teachingClassConflictList != null && !teachingClassConflictList.isEmpty()) {
            //将之前数据库记录的冲突信息全部删除掉
            arrangeCourseDataSource.removeConflictList(teachingClassConflictList);
            //定义迭代器
            Iterator iterator = teachingClassConflictList.iterator();
            //筛选调整前与当前教学班冲突，但是调整后与当前教学班不冲突了的，冲突信息
            while (iterator.hasNext()) {
                //获取冲突信息
                ScheduleConflictInfo conflict = (ScheduleConflictInfo) iterator.next();
                //如果新生成的冲突列表中，包括原来的冲突信息
                if (conflictList.contains(conflict)) {
                    //从原来的冲突信息中，删除掉
                    //这样原来的冲突信息中，剩下的就是，之前与当前教学班冲突的教学班的冲突信息了
                    iterator.remove();
                }
            }
            //如果之前存在冲突,调整之后，没出冲突了，这时需要对原来冲突的教学班进行标志，修改为已排(无冲突)
            updateStateByConflictList(teachingClassConflictList, ScheduleState.NORMAL.getCode());
        }
    }

    /**
     * 根据冲突信息列表，更新教学班的排课状态
     *
     * @param conflictList  冲突信息列表
     * @param scheduleState 更新状态，1已排（正常）、2已排（冲突）、3待排
     */
    @Override
    public void updateStateByConflictList(List<ScheduleConflictInfo> conflictList,
                                          Integer scheduleState) {
        if (conflictList != null && !conflictList.isEmpty()) {
//            //提取列表中的教学班id，并去重，生成列表
//            List<Long> teachingClassIdList = conflictList.stream()
//                    .map(conflict -> conflict.getTeachingClassId())
//                    .distinct()
//                    .collect(Collectors.toList());

            //更新教学班排课状态
//            updateSchedualState(teachingClassIdList, scheduleState);
            updateClashSchedualState(conflictList, scheduleState);
        }
    }

    private void updateClashSchedualState(List<ScheduleConflictInfo> conflictList,
                                          Integer scheduleState) {
        //提取列表中的教学班id，并去重，生成列表
        List<Long> teachingClassIdList = conflictList.stream()
                .map(conflict -> conflict.getTeachingClassId())
                .distinct()
                .collect(Collectors.toList());
        List<TeachingClassWeek> weeks = teachingClassWeekService.lambdaQuery()
                .in(TeachingClassWeek::getTeachingClassId, teachingClassIdList)
                .eq(TeachingClassWeek::getDeleted, Deleted.NOT.getCode()).list();


        List<TeachingClassWeek> batch = new ArrayList<>();

        for (ScheduleConflictInfo conflictInfo : conflictList) {

            List<TeachingClassWeek> update = weeks.stream().filter(o -> o.getTeachingClassId().equals(conflictInfo.getTeachingClassId())
                            && o.getHourType().equals(conflictInfo.getHourType()))
                    .collect(Collectors.toList());
//            update.forEach(o -> o.setScheduleState(scheduleState));
            update.get(0).setScheduleState(scheduleState);
            batch.addAll(update);

        }
        teachingClassWeekService.updateBatchById(batch);

    }

    /**
     * 更新指定教学班的排课冲突状态信息
     *
     * @param teachingClassIds 教学班id列表
     * @param scheduleState    更新状态，1已排（正常）、2已排（冲突）、3待排
     */
    private void updateSchedualState(List<Long> teachingClassIds,
                                     Integer scheduleState,
                                     CopyOnWriteArrayList<ClassHour> classHourList) {
        if (teachingClassIds != null
                && !teachingClassIds.isEmpty()) {
            //初始化返回列表信息
//            List<ArrangeTeachingClassUpdate> updateList = new ArrayList<>();
//            for (Long teachingClassId : teachingClassIds) {
//                //生成更新列表信息；
//                updateList.add(new ArrangeTeachingClassUpdate(teachingClassId, scheduleState));
//            }

//            //将未分配教室的，教学班冲突状态进行更新；
//            arrangeCourseDataSource.updateScheduleState(updateList);

            List<TeachingClassWeek> weeks = teachingClassWeekService.lambdaQuery()
                    .in(TeachingClassWeek::getTeachingClassId, teachingClassIds)
                    .eq(TeachingClassWeek::getDeleted, Deleted.NOT.getCode()).list();

/*
            List<TeachingClassWeek> batch = new ArrayList<>();
            List<CourseUnit> courseUnitList = classHourList.stream().map(ClassHour::getCourseUnit).collect(Collectors.toList());
            Map<Long, List<CourseUnit>> map = courseUnitList.stream().collect(Collectors.groupingBy(CourseUnit::getTeachingClassId));
            for (Long id : map.keySet()) {
                for (CourseUnit courseUnit : map.get(id)) {
                    List<TeachingClassWeek> update = weeks.stream().filter(o -> o.getTeachingClassId().equals(id) && o.getHourType().equals(courseUnit.getTeachingType()))
                            .collect(Collectors.toList());
                    update.get(0).setScheduleState(scheduleState);
                    batch.addAll(update);
                }
            }
 */
            weeks.forEach(o -> o.setScheduleState(scheduleState));
            teachingClassWeekService.updateBatchById(weeks);
        }
    }

    /**
     * 移除指定教学班禁排的教室课时分组信息
     *
     * @param teachingClass    指定的教学班信息
     * @param timeslotRoomList 当前空闲的，所有的教室课时分组信息
     * @return
     */
    private LinkedList<TimeslotRoom> removePhrohibitRuleTimeslotRoom(ArrangeTeachingClassDto teachingClass,
                                                                     LinkedList<TimeslotRoom> timeslotRoomList) {
        if (teachingClass == null
                || timeslotRoomList == null
                || timeslotRoomList.isEmpty()) {
            log.info("ArrangeCourseServiceImpl--->> removeTeachingClassPhrohibitTimeslot---->>Excetption:data is null!!");
            return null;
        }
        if (StrUtil.isEmpty(teachingClass.getProhibitTimeslotCodes())) {
            return timeslotRoomList;
        }
        //定义列表遍历的迭代器
        Iterator iterator = timeslotRoomList.iterator();
        while (iterator.hasNext()) {
            TimeslotRoom timeslotRoom = (TimeslotRoom) iterator.next();
            if (teachingClass.getProhibitTimeslotCodes().contains(timeslotRoom.getTimeslotCode())) {
                iterator.remove();
            }
        }

        return timeslotRoomList;
    }

    /**
     * 根据教学班的周次，找出符合要求的教室课时分组信息；
     *
     * @param timeslotRoomList 教室课时分组信息列表
     * @param classWeeks       教学班排课所需的周次
     * @return
     */
    private LinkedList<TimeslotRoom> filterTimeslotRoomByWeeks(LinkedList<TimeslotRoom> timeslotRoomList,
                                                               String classWeeks) {
        if (timeslotRoomList != null && !timeslotRoomList.isEmpty()) {
            //定义迭代器
            Iterator iterator = timeslotRoomList.iterator();
            while (iterator.hasNext()) {
                TimeslotRoom timeslotRoom = (TimeslotRoom) iterator.next();
                //获取教室课时分组的周次
                String timeslotRoomWeeks = timeslotRoom.getWeeks();
                //将两个二进制字符串，进行与操作,比如10101和11111，进行与操作，结果是10101
                String result = BinaryUtil.binaryAnd(timeslotRoomWeeks, classWeeks);
                //如果结果字符串和教学班的周次不相等，说明当前教室课时分组的周次，是不符合当前教学班的周次需求的
                if (!result.equals(classWeeks)) {
                    //那么，需要将这个教室课时分组信息，从列表删除掉
                    iterator.remove();
                }
            }
        }

        return timeslotRoomList;
    }


    /**
     * 算法排课
     *
     * @param taskId 排课计划id
     */
    @Override
    public void algService(Integer taskId) {
        //获取学期排课选课计划信息
        TaskInfo taskInfo = arrangeCourseDataSource.getTaskInfo(taskId);
        if (taskInfo != null) {
            log.info("#ArrangeCourseServiceImpl.algService#--开始自动排课，taskId为{}的计划信息获取成功", taskId);
            //0各校区独立排课 1全校统一排课
            Integer crossCampusOption = taskInfo.getUnifiedCampus();
            //学校id
            String schoolId = taskInfo.getSchoolId();
            //学期id
            String termId = taskInfo.getTerm();

            /*
            无冲突会打破固排规则
            跨校区排课时 会打破禁排规则
             */
            //开启跨校区排课，全校所有的课程，将安排到所有校区的教室
            ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> retMap = startScheduling(schoolId, termId, taskId, crossCampusOption);

            log.info("排课完成,taskId={}，记录课表",taskId);

//            将排课的数据，进行冲突检测、教学班排课状态标记，最后同步写入数据库；
            syncData2DB(taskId, retMap);
            log.info("排课完成,taskId={}，课表保存成功",taskId);
        }
    }

    /**
     * 开启排课
     *
     * @param schoolId          学校id
     * @param termId            学期id
     * @param taskId            学期排课计划id
     * @param crossCampusOption 跨校区排课标识，1：跨校区排课，0：各校区独立排课
     */
    private ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> startScheduling(String schoolId,
                                                                                       String termId,
                                                                                       Integer taskId,
                                                                                       Integer crossCampusOption) {
        //获取排课教学班数据；
        List<ArrangeTeachingClassDto> teachingClassList = arrangeCourseDataSource.getTeachingClassList(taskId, null);
        log.info("#ArrangeCourseServiceImpl.startScheduling#--获取到{}个排课教学班", teachingClassList.size());
        if (teachingClassList != null && !teachingClassList.isEmpty()) {
            //获取学期的周次信息
            /*
            总周次 List：每一周次开始结束时间
             */
            WeekDateVo weekInfo = arrangeCourseDataSource.getTermWeeks(taskId);
            //获取学期总周数，默认16周
            Long weekNum = 16L;
            if (weekInfo != null) {
                //获取学期总周数
                weekNum = weekInfo.getWeekCount();
                log.info("#ArrangeCourseServiceImpl.startScheduling#--学期总周数信息获取成功，当前学期共{}周", weekNum);
            }

            //获取基础排课规则信息；
             /*
            new BaseRule(crossCampusOption, courseDistribution, teacherDistribution, maxSection);
            是否跨区  课程分布 教师分布 教师最大上课次数 禁排规则
             */
            BaseRule baseRule = getScheduleRule(schoolId, termId, taskId, crossCampusOption);
            log.info("#ArrangeCourseServiceImpl.startScheduling#--基础规则信息获取完成");

            //获取排课教室数据
            /*
            全部教室信息 同一学期只同步一次教室
             */
            List<ArrangeRoomDto> roomList = arrangeCourseDataSource.getRoomList(schoolId, termId, null);
            log.info("#ArrangeCourseServiceImpl.startScheduling#--排课教室信息获取完成，共{}间教室", (roomList != null ? roomList.size() : 0));

            //获取排课课时数据；
             /*
            周每一天的课时信息
             */
            List<ArrangePeriod> timeslotList = arrangeCourseDataSource.getTimeslotList(taskId, schoolId, termId);
            log.info("#ArrangeCourseServiceImpl.startScheduling#--排课课时信息获取完成，共{}个课时", (timeslotList != null ? timeslotList.size() : 0));


            /*
            ==========================基础规则启用判断==========================
             */

            /*
            教学班id 禁排课时信息 0402
             */
            //获取教学班规则数据 包含 固排 禁排
            List<ArrangeTeachingClassRuleDto> teachingClassRuleList = arrangeCourseDataSource.getTeachingClassRuleList(taskId);
            assert baseRule != null;
            teachingClassRuleList = arrangeCourseDataSource.filterTeachingClassRule(baseRule, teachingClassRuleList);
            log.info("#ArrangeCourseServiceImpl.startScheduling#--教学班规则信息获取完成，共{}条规则", (teachingClassRuleList != null ? teachingClassRuleList.size() : 0));

            /*
            教室id和课时信息 ==》 451 -- 0401
             */
            List<ArrangeRoomRuleDto> roomProhibitList = new ArrayList<>();
            if ("b".equals(baseRule.getRoomRuleEnable())) {
                //获取教室禁排数据
                roomProhibitList = arrangeCourseDataSource.getRoomRuleList(taskId, schoolId, termId, null);
                log.info("#ArrangeCourseServiceImpl.startScheduling#--教室禁排规则信息获取完成，共{}条规则", (roomProhibitList != null ? roomProhibitList.size() : 0));
            }

            //教室固排不启用删除教室固排
            if ("a".equals(baseRule.getRoomFixEnable())) {
                if (CollUtil.isNotEmpty(teachingClassRuleList)) {
                    teachingClassRuleList = teachingClassRuleList.stream()
                            .filter(o -> o.getType() == null || o.getType() != FixType.Room.getCode())
                            .collect(Collectors.toList());
                }
            }

            /*
            教师id 禁排课时 ==》 2796 -- 0301
             */
            List<ArrangeTeacherRuleDto> teacherRuleList = new ArrayList<>();
            if ("b".equals(baseRule.getTeacherRuleEnable())) {
                //获取教师排课规则
                teacherRuleList = arrangeCourseDataSource.getTeacherRuleList(taskId, schoolId, termId);
                log.info("#ArrangeCourseServiceImpl.startScheduling#--教师规则信息获取完成，共{}条规则", (teacherRuleList != null ? teacherRuleList.size() : 0));
            }
            //教师固排不启用删除教师固排
            if ("a".equals(baseRule.getTeacherFixEnable())) {
                if (CollUtil.isNotEmpty(teachingClassRuleList)) {
                    teachingClassRuleList = teachingClassRuleList.stream()
                            .filter(o -> o.getType() == null || o.getType() != FixType.Teacher.getCode())
                            .collect(Collectors.toList());
                }
            }

            /*
            课程id 禁排课时信息 0402
             */
            List<ArrangeCourseRuleDto> courseRuleList = new ArrayList<>();
            if ("b".equals(baseRule.getCourseRuleEnable())) {
                //获取课程禁排数据
                courseRuleList = arrangeCourseDataSource.getCourseRuleList(taskId);
                log.info("#ArrangeCourseServiceImpl.startScheduling#--课程规则信息获取完成，共{}条规则", (courseRuleList != null ? courseRuleList.size() : 0));
            }
            //课程固排不启用删除课程固排
            if ("a".equals(baseRule.getCourseFixEnable())) {
                if (CollUtil.isNotEmpty(teachingClassRuleList)) {
                    teachingClassRuleList = teachingClassRuleList.stream()
                            .filter(o -> o.getType() == null || o.getType() != FixType.Course.getCode())
                            .collect(Collectors.toList());
                }
            }
            teachingClassRuleList = arrangeCourseDataSource.removeProhibitFromCourse(taskId,schoolId,termId,teachingClassRuleList);

            /*
            行政班id 禁排课时信息 0402
             */
            List<ArrangeClassRuleDto> classRuleList = new ArrayList<>();
            if ("b".equals(baseRule.getClassRuleEnable())) {
                //获取行政班禁排数据
                classRuleList = arrangeCourseDataSource.getclassRuleList(taskId);
                log.info("#ArrangeCourseServiceImpl.startScheduling#--行政班规则信息获取完成，共{}条规则", (classRuleList != null ? classRuleList.size() : 0));
            }
            //行政班固排不启用删除行政班固排
            if ("a".equals(baseRule.getClassFixEnable())) {
                if (CollUtil.isNotEmpty(teachingClassRuleList)) {
                    teachingClassRuleList = teachingClassRuleList.stream()
                            .filter(o -> o.getType() == null || o.getType() != FixType.Class.getCode())
                            .collect(Collectors.toList());
                }
            }
            log.info("#ArrangeCourseServiceImpl.startScheduling#--教学班规则信息获取完成，共{}条规则", (teachingClassRuleList != null ? teachingClassRuleList.size() : 0));
            /*
            ================================================================
             */

            //取指定学校，已结束排课计划以及当前排课计划已锁定的课表信息
            List<ArrangeScheduleDto> scheduleList = arrangeCourseDataSource.getLockedScheduleList(
                    taskId, null, 2, null);
            log.info("#ArrangeCourseServiceImpl.startScheduling#--同学期其他计划以及本计划锁定的课表信息获取完成，共{}条记录",
                    (scheduleList != null ? scheduleList.size() : 0));

            //将获取的锁定的课表，转换成ClassHour排课课时对象
            CopyOnWriteArrayList<ClassHour> lockedClassHourList = convertor.convertToClassHourList(scheduleList, timeslotList);
            log.info("#ArrangeCourseServiceImpl.startScheduling#--数据库课表数据转换成排课课表数据完成，共{}条记录",
                    (lockedClassHourList != null ? lockedClassHourList.size() : 0));

            //将列表，按照timeslotCode，进行分组，即作为key，生成map
            ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> classHourMap = ClassHourUtil.getClassHourMap(lockedClassHourList);

            log.info("#ArrangeCourseServiceImpl.startScheduling#--开始校区排课");
            //开启校区排课
            classHourMap = new SchoolScheduling().start(taskId,//排课选课计划id
                    teachingClassList, //教学班排课单元信息
                    roomList, //教室信息；
                    timeslotList, //排课课时信息
                    roomProhibitList,//禁排的教室列表信息；
                    classHourMap, //锁定的排课单元信息
                    teacherRuleList,//教师规则列表信息
                    courseRuleList,//课程规则列表信息；
                    classRuleList,//行政班规则列表信息；
                    teachingClassRuleList,//教学班规则列表信息；
                    baseRule,//是否跨校区排课标识
                    weekNum, arrangeProcessService);//学期总周数
            log.info("ArrangeCourseServiceImpl.startScheduling--校区排课结束");
//            StopWatch stopWatch = new StopWatch();
//            stopWatch.start("计算冲突数");
//            int clashes = clashesProcess.calcClashes(classHourMap);
//            stopWatch.stop();
//            log.info("计算冲突数：" + clashes + "，耗时："+ stopWatch.getLastTaskTimeMillis());

            return classHourMap;
        }

        return null;
    }

    /**
     * 获取排课规则，自定排课的时候，进行处理
     *
     * @param taskId            计划id
     * @param crossCampusOption 跨校区排课规则
     * @return
     */
    private BaseRule getScheduleRule(String schoolId, String termId, Integer taskId, Integer crossCampusOption) {
        List<RuleUsable> ruleList = arrangeCourseDataSource.getBaseRuleList(null, null, taskId);
        if (ruleList != null && !ruleList.isEmpty()) {
            //课程分布
            String courseDistribution = "a";
            //教师分布
            String teacherDistribution = "a";
            //教师每天最大的上课节次
            Integer maxSection = Integer.MAX_VALUE;

            //环节排课，a无需求，b环节所在周次不怕苦
            String segmentArrange = "a";
            //场地禁排，a不启用，b启用
            String roomRuleEnable = "a";
            //教师禁排，a不启用，b启用
            String teacherRuleEnable = "a";
            //教师单日上课限制，a不启用，b启用
            String teacherLimitEnable = "a";
            //行政班禁排，a不启用，b启用
            String classRuleEnable = "a";
            //教学班禁排，a不启用，b启用
            String teachingClassRuleEnable = "a";
            //课程禁排，a不启用，b启用
            String courseRuleEnable = "a";

            //场地固排，a不启用，b启用
            String roomFixEnable = "a";
            //教师固排，a不启用，b启用
            String teacherFixEnable = "a";
            //行政班固排，a不启用，b启用
            String classFixEnable = "a";
            //教学班固排，a不启用，b启用
            String teachingClassFixEnable = "a";
            //课程固排，a不启用，b启用
            String courseFixEnable = "a";

            //课时禁排，a不启用，b启用
            String timeRuleEnable = "a";
            //跨校区时间，a不启用，b半天 c一天
            String crossCampusRule = "a";

            String baseRuleEnable = "a";

            //手动调整 教室容量判断
            String capacityCheck = "a";

            //获取用户设置的教师、课程分布情况
            for (RuleUsable rule : ruleList) {
                //规则类型
                Integer code = rule.getCode();
                //用户选项
                String option = rule.getOption();
                //基础规则
                /**
                 * 1：跨校区 a 无规则 b 半天 c 一天；
                 * 2：教师分布；3课程分布；4：教案平齐；5：环节排课
                 * 6 场地禁排 7 教师禁排 8 教师上课节次限制 9 行政班禁排 10 教学班禁排 11 课程禁排 12 课时禁排
                 * 13:课时方案选择  a:统一设置  b:单一设置
                 * 14 场地固排 15 教师固排 16 行政班固排 17 教学班固排 18 课程固排
                 * 19 基础规则
                 */
                switch (code) {
                    case 1:
                        crossCampusRule = option;
                        break;
                    case 2:
                        teacherDistribution = option;
                        break;
                    case 3:
                        courseDistribution = option;
                        break;
                    case 5:
                        segmentArrange = option;
                        break;
                    case 6:
                        roomRuleEnable = option;
                        break;
                    case 7:
                        teacherRuleEnable = option;
                        break;
                    case 8:
                        teacherLimitEnable = option;
                        break;
                    case 9:
                        classRuleEnable = option;
                        break;
                    case 10:
                        teachingClassRuleEnable = option;
                        break;
                    case 11:
                        courseRuleEnable = option;
                        break;
                    case 12:
                        timeRuleEnable = option;
                        break;

                    case 14:
                        roomFixEnable = option;
                        break;
                    case 15:
                        teacherFixEnable = option;
                        break;
                    case 16:
                        classFixEnable = option;
                        break;
                    case 17:
                        teachingClassFixEnable = option;
                        break;
                    case 18:
                        courseFixEnable = option;
                        break;
                    case 19:
                        baseRuleEnable = option;
                        break;
                    case 20:
                        capacityCheck = option;
                        break;
                }
//                if (code == 2) {
//                    teacherDistribution = option;
//                } else if (code == 3) {//课程分布
//                    courseDistribution = option;
//                }
            }

            if ("b".equals(teacherLimitEnable)) {
                //获取教师规则设置信息
                RuleTeacherSetting setting = arrangeCourseDataSource.getTeacherSetting(taskId);
                //获取设置的教师单日最大上课节次信息
                maxSection = setting.getMaxSection();
            }

            if ("a".equals(baseRuleEnable)) {
                //课程分布
                courseDistribution = "a";
                //教师分布
                teacherDistribution = "a";
                //环节排课
                segmentArrange = "a";
                //跨校区
                crossCampusRule = "a";
            }

            log.info("#ArrangeCourseServiceImpl.getScheduleRule#--跨校区规则标识为：" + crossCampusOption
                    + "基础规则：" + baseRuleEnable
                    + "跨校区时间为：" + crossCampusRule
                    + "课时禁排为：" + timeRuleEnable
                    + "基础规则设置的课程范围为：" + courseDistribution
                    + ", 教师范围为：" + teacherDistribution
                    + ", 环节为：" + segmentArrange
                    + ", 教室固排禁排为：" + roomRuleEnable
                    + ", 教师固排禁排为：" + teacherRuleEnable
                    + ", 行政班固排禁排为：" + classRuleEnable
                    + ", 教学班固排禁排为：" + teachingClassRuleEnable
                    + ", 课程固排禁排为：" + classRuleEnable
                    + ", 教室容量检测为：" + capacityCheck
                    + "，教师单日最大上课节次为：" + maxSection);
            return new BaseRule(crossCampusOption, courseDistribution, teacherDistribution, maxSection,
                    segmentArrange, roomRuleEnable, teacherRuleEnable, teacherLimitEnable, classRuleEnable,
                    teachingClassRuleEnable, courseRuleEnable, timeRuleEnable, crossCampusRule,
                    roomFixEnable, teacherFixEnable, classFixEnable, teachingClassFixEnable, courseFixEnable,
                    baseRuleEnable,capacityCheck);
        }
        log.error("#ArrangeCourseServiceImpl.getScheduleRule#--基础规则信息获取失败");
        return null;
    }

    /**
     * 将排课的数据，进行冲突检测、教学班排课状态标记，最后同步写入数据库；
     *
     * @param taskId       计划id
     * @param classHourMap 排课课表数据map
     */
    private void syncData2DB(Integer taskId,
                             ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> classHourMap) {
        if (classHourMap != null && !classHourMap.isEmpty()) {
            //将排课数据，转换为数据库实体类对象列表
            //通过taskId，过滤掉了不是当前排课计划的课表单元数据
            List<Schedule> resultScheduleList = convertor.convertToScheduleList(classHourMap);
            resultScheduleList = resultScheduleList.stream().filter(o -> o.getTaskId().equals(taskId)).collect(Collectors.toList());
            log.info("ArrangeCourseServiceImpl.syncData2DB--排课课表转换成数据库课表数据完成，共生成{}条记录",
                    (resultScheduleList != null ? resultScheduleList.size() : 0));

            //将排课结果，记录到数据库表中
            arrangeCourseDataSource.addBathSchedule(taskId, resultScheduleList);
            log.info("ArrangeCourseServiceImpl.syncData2DB--课表数据写入数据库成功");

            //将排课冲突信息，写入数据库进行记录
            List<ScheduleConflictInfo> conflictList = recordClashes(taskId, classHourMap);
            log.info("ArrangeCourseServiceImpl.syncData2DB--校区排课完成");

            //更新教学班的排课状态信息，先处理未排的，然后处理已排（无冲突），最后处理已排（冲突）
            updateTeachingClassScheduleState(taskId, classHourMap, conflictList);
        }
    }

    /**
     * 记录冲突，将冲突写入数据库
     *
     * @param taskId       排课选课计划id
     * @param classHourMap 排完课的，课程课时map信息
     */
    private List<ScheduleConflictInfo> recordClashes(Integer taskId,
                                                     ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> classHourMap) {
        //定义存储冲突记录的列表
        List<ScheduleConflictInfo> conflictList = new ArrayList<>();

        //获取存在冲突的排课单元信息
        CopyOnWriteArrayList<ClassHour> clashesTimeslotRoomList = classHourMap.get("ClashesTimeslotRoom");

        if (clashesTimeslotRoomList != null && !clashesTimeslotRoomList.isEmpty()) {
            log.info("#ArrangeCourseServiceImpl.recordClashes#--存在冲突的教学班排课记录，共{}条",
                    (clashesTimeslotRoomList != null ? clashesTimeslotRoomList.size() : 0));
            //map的key为排课单元id，即CourseUnitId
            Map<Integer, List<ScheduleConflictInfo>> conflictMap = new HashMap<>();
            //将存在冲突的排课单元，进行冲突记录
            conflictMap = clashesProcess.recordTimeslotRoomClashes(classHourMap,
                    clashesTimeslotRoomList, conflictMap);
            log.info("#ArrangeCourseServiceImpl.recordClashes#--冲突检测完成，冲突记录已生成");
            //如果map中存在数据；
            if (!conflictMap.isEmpty()) {
                //将冲突记录的map，转换成list
                conflictList = conflictMap.entrySet().stream()
                        .flatMap(entry -> entry.getValue().stream())
                        .collect(Collectors.toList());
                log.info("#ArrangeCourseServiceImpl.recordClashes#--生成冲突记录，共{}条",
                        (conflictList != null ? conflictList.size() : 0));

            }
        }

        //写入数据库冲突表
        arrangeCourseDataSource.addBatchScheduleConflict(taskId, conflictList);
        log.info("#ArrangeCourseServiceImpl.recordClashes#--排课冲突记录写入数据库完成，共{}条记录",
                (conflictList != null ? conflictList.size() : 0));

        return conflictList;
    }

    /**
     * 更新教学班的排课状态信息，先处理未排的，然后处理已排（无冲突），最后处理已排（冲突）
     *
     * @param classHourMap 排课课表信息列表
     * @param conflictList 冲突信息列表
     */
    private void updateTeachingClassScheduleState(Integer taskId, ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> classHourMap,
                                                  List<ScheduleConflictInfo> conflictList) {
        //更新无冲突课程的，教学班的排课状态信息，为1，已排（无冲突）；
        updateNoclashScheduleState(taskId, classHourMap);
        log.info("ArrangeCourseServiceImpl.updateTeachingClassScheduleState--更新无冲突的教学班的排课状态为：已排（无冲突）--完成");
        log.info("#ArrangeCourseServiceImpl.updateTeachingClassScheduleState#--排课冲突的教学班排课课表记录，共{}条",
                (conflictList != null ? conflictList.size() : 0));

        //更新无冲突课程的，教学班的排课状态信息，为2，已排（未满足规则）；
        updateUnsuitableScheduleState(taskId, classHourMap);
        log.info("ArrangeCourseServiceImpl.updateTeachingClassScheduleState--更新无冲突的教学班的排课状态为：已排（未满足规则）--完成");
        log.info("#ArrangeCourseServiceImpl.updateTeachingClassScheduleState#--排课冲突的教学班排课课表记录，共{}条",
                (conflictList != null ? conflictList.size() : 0));

        //获取未指定教室课时分组信息的，排课单元信息
        CopyOnWriteArrayList<ClassHour> noTimeslotRoomList = classHourMap.get("NoTimeslotRoom");
        if (noTimeslotRoomList != null && noTimeslotRoomList.size() > 0) {
//           将未指定教室课时分组信息，作为冲突记录，进行记录
//            clashesRecordList = clashesProcess.recordNoTimeslotRoomClashes(noTimeslotRoomList, clashesRecordList);
            log.info("#ArrangeCourseServiceImpl.updateTeachingClassScheduleState#--未分配教室课时的教学班排课课表记录，共{}条",
                    (noTimeslotRoomList != null ? noTimeslotRoomList.size() : 0));
            //更新未分配教室的教学班的，排课状态信息为4：待排
            updateStateByClassHourList(noTimeslotRoomList, ScheduleState.UNARRANGE.getCode());
            log.info("ArrangeCourseServiceImpl.updateTeachingClassScheduleState--更新未分配教室课时的教学班的排课状态为：待排--完成");
        }

        //更新存在冲突的教室的教学班的，排课状态信息为3：已排（冲突）
        //这个要放在最后更新，因为正常排课的课程，在分配冲突教室之后，还会产生新的冲突；
        //所以这个放在更新正常的教学班的排课状态之后，可以对之前的更新（updateNoclashScheduleState），进行覆盖
        updateStateByConflictList(conflictList, ScheduleState.CONFLICT.getCode());
        log.info("ArrangeCourseServiceImpl.updateTeachingClassScheduleState--更新排课冲突的教学班的排课状态为：已排（冲突）--完成");
    }

    /**
     * 更新无冲突的课程，教学班的排课冲突状态信息；
     *
     * @param classHourMap 课表map，以timeslotCode作为key，即0101代表，周一第一节
     */
    private void updateNoclashScheduleState(Integer taskId, ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> classHourMap) {
        if (classHourMap != null && !classHourMap.isEmpty()) {
            CopyOnWriteArrayList<ClassHour> noClashList = new CopyOnWriteArrayList<>();
            //取出无冲突课程的课表列表
            for (Map.Entry<String, CopyOnWriteArrayList<ClassHour>> entry : classHourMap.entrySet()) {
                //获取map的key
                String key = entry.getKey();
                //获取正常无冲突的课程课表
                if (!key.equals("NoTimeslotRoom")
                        && !key.equals("ClashesTimeslotRoom")) {
                    //将正常的列表信息，加入新的列表
                    noClashList.addAll(entry.getValue());
                }
            }
            log.info("#ArrangeCourseServiceImpl.updateNoclashScheduleState#--无冲突的排课记录，共{}条",
                    (noClashList != null ? noClashList.size() : 0));
            if (noClashList != null && !noClashList.isEmpty()) {
                //提取列表中的教学班id，并去重，生成列表
                List<Long> teachingClassIdList = noClashList.stream()
                        .map(classHour -> classHour.getCourseUnit().getTeachingClassId())
                        .distinct()
                        .collect(Collectors.toList());
                log.info("#ArrangeCourseServiceImpl.updateNoclashScheduleState#--无冲突的排课记录对应的教学班，共{}个",
                        (teachingClassIdList != null ? teachingClassIdList.size() : 0));
                //将教学班排课状态设为，1已排（正常）
//                updateSchedualState(teachingClassIdList, ScheduleState.NORMAL.getCode(), noClashList);

                List<CourseUnit> courseUnitList = noClashList.stream()
                        .map(ClassHour::getCourseUnit)
                        .distinct()
                        .filter(o -> o.getTaskId().equals(taskId))
                        .collect(Collectors.toList());

                //过滤锁定的非正常的
                List<TeachingClassWeek> week = teachingClassWeekMapper.getUnNormal(taskId);
                if (CollUtil.isNotEmpty(week)){
                    Map<Long, List<TeachingClassWeek>> map = week.stream().collect(Collectors.groupingBy(TeachingClassWeek::getTeachingClassId));
                    Set<Long> keys = map.keySet();
                    courseUnitList = courseUnitList.stream().filter(o -> {
                        Long teachingClassId = o.getTeachingClassId();
                        if (!keys.contains(teachingClassId)){
                            return true;
                        }
                        List<TeachingClassWeek> teachingClassWeeks = map.get(teachingClassId);
                        List<Integer> types = teachingClassWeeks.stream().map(TeachingClassWeek::getHourType).collect(Collectors.toList());
                        if (types.contains(o.getTeachingType())){
                            return false;
                        }
                        return true;
                    }).collect(Collectors.toList());
                }
                updateSchedualState(ScheduleState.NORMAL.getCode(), courseUnitList);
            }
        }

    }

    private void updateSchedualState(int code, List<CourseUnit> courseUnitList) {
        if (CollUtil.isNotEmpty(courseUnitList)) {
            teachingClassWeekMapper.updateScheduleState(code, courseUnitList);
        }
    }

    private void updateStateByTeachingClasss(List<ScheduleConflictInfo> noConflictTeachingClass, int code) {
        if (CollUtil.isNotEmpty(noConflictTeachingClass)) {
            teachingClassWeekMapper.updateScheduleState1(code, noConflictTeachingClass);
        }
    }


    /**
     * 更新无冲突的课程，教学班的排课冲突状态信息  未满足规则的；
     *
     * @param classHourMap 课表map，以timeslotCode作为key，即0101代表，周一第一节
     */
    private void updateUnsuitableScheduleState(Integer taskId, ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> classHourMap) {
        if (classHourMap != null && !classHourMap.isEmpty()) {
            CopyOnWriteArrayList<ClassHour> noClashList = new CopyOnWriteArrayList<>();
            //取出无冲突课程的课表列表
            for (Map.Entry<String, CopyOnWriteArrayList<ClassHour>> entry : classHourMap.entrySet()) {
                //获取map的key
                String key = entry.getKey();
                //获取正常无冲突的课程课表
                if (!key.equals("NoTimeslotRoom")
                        && !key.equals("ClashesTimeslotRoom")) {
                    //将正常的列表信息，加入新的列表
                    noClashList.addAll(entry.getValue());
                }
            }
            log.info("#ArrangeCourseServiceImpl.updateUnsuitableScheduleState#--无冲突的排课记录，共{}条",
                    (noClashList != null ? noClashList.size() : 0));
            if (noClashList != null && !noClashList.isEmpty()) {

                HashSet<Long> unsuitableTeachingClassIds = new HashSet<>();
                List<CourseUnit> unsuitableCourseUnits = new ArrayList<>();
                for (ClassHour classHour : noClashList) {
                    CourseUnit courseUnit = classHour.getCourseUnit();
                    if(!courseUnit.getTaskId().equals(taskId)){
                        continue;
                    }
                    Long teachingClassId = courseUnit.getTeachingClassId();
                    String fixRoomId = courseUnit.getRoomId();
                    List<String> fixTimeslotCodes = courseUnit.getFixTimeslotCodes();
//                    if (fixTimeslotCodes.contains("")) {
//                        fixTimeslotCodes = null;
//                    }
                    String prohibitTimeslotCodes = courseUnit.getProhibitTimeslotCodes();
                    TimeslotRoom timeslotRoom = classHour.getTimeslotRoom();
                    Long curRoomId = timeslotRoom.getRoomId();
                    String timeCode = timeslotRoom.getTimeslotCode();


                    //教室
//                    if (StrUtil.isNotEmpty(fixRoomId) && !fixRoomId.equals(String.valueOf(curRoomId))) {
////                        unsuitableTeachingClassIds.add(teachingClassId);
//                        unsuitableCourseUnits.add(courseUnit);
//                        continue;
//                    }
                    //固排
                    if (CollUtil.isNotEmpty(fixTimeslotCodes)){
                        //一个固排 连上 出现问题
                        if (fixTimeslotCodes.size() == 1) {
                            Integer connectSection = courseUnit.getConnectSection();
                            if (connectSection > 1){
                                Integer fixTime = Integer.valueOf(fixTimeslotCodes.get(0));
                                Integer time = Integer.valueOf(timeCode);
                                if (Math.abs(time-fixTime) > connectSection -1){
                                    unsuitableCourseUnits.add(courseUnit);
                                    continue;
                                }
                            }else {
                                if (!fixTimeslotCodes.contains(timeCode)) {
                                    unsuitableCourseUnits.add(courseUnit);
                                    continue;
                                }
                            }
                        }
                        if (fixTimeslotCodes.size() > 1
                                && !fixTimeslotCodes.contains(timeCode)) {
//                        unsuitableTeachingClassIds.add(teachingClassId);
                            unsuitableCourseUnits.add(courseUnit);
                            continue;
                        }
                    }
                    //禁排
                    if (StrUtil.isNotEmpty(prohibitTimeslotCodes) && prohibitTimeslotCodes.contains(timeCode)) {
//                        unsuitableTeachingClassIds.add(teachingClassId);
                        unsuitableCourseUnits.add(courseUnit);
                    }
                }
                log.info("#ArrangeCourseServiceImpl.updateUnsuitableScheduleState#--无冲突的排课为满足规则的教学班，共{}个",
                        (unsuitableCourseUnits != null ? unsuitableCourseUnits.size() : 0));

                //将教学班排课状态设为，2已排（未满足规则）
                updateSchedualState(ScheduleState.UNSUITABLE.getCode(), unsuitableCourseUnits);
            }
        }

    }

}
